#include "QcDictDirModel.h"

QcDictDirModel::QcDictDirModel(QObject *parent)
    : QFileSystemModel(parent)
{
    setReadOnly(true);
    setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
    setOptions(QFileSystemModel::DontWatchForChanges | QFileSystemModel::DontResolveSymlinks);
}

Qt::ItemFlags QcDictDirModel::flags(const QModelIndex &index) const
{
    return QFileSystemModel::flags(index) | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate;
}

QVariant QcDictDirModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::CheckStateRole) {
        auto pos = checkStates_.constFind(filePath(index));
        if (pos == checkStates_.constEnd())
            return Qt::Unchecked;

        return pos.value();
    }

    return QFileSystemModel::data(index, role);
}

bool QcDictDirModel::setCheckState_(const QModelIndex &index,int state)
{
    auto path = filePath(index);
    if (state == Qt::Unchecked)
        checkStates_.remove(path);
    checkStates_[path] = state;

    emit dataChanged(index, index, { Qt::CheckStateRole });

    // 通知父节点，直接告诉父节点半选即可
    if(index.parent().isValid())
        return setData(index.parent(), Qt::PartiallyChecked, Qt::CheckStateRole);

    return true;
}

bool QcDictDirModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(role != Qt::CheckStateRole)
        return QFileSystemModel::setData(index, value, role);

    if (data(index, role).toInt() == role)
        return true;

    //针对复选框变动做操作
    auto state = value.toInt();
    switch (state) {
    case Qt::Unchecked:
    case Qt::Checked:
        for(int i = 0; i < rowCount(index); i++)
            setData(this->index(i, 0, index), state, role);

        //修改内容-必须先修改自己再通知父节点
        return setCheckState_(index, state);

    case Qt::PartiallyChecked: { //半选
        bool allChecked(true), allUnchecked(true);

        //遍历所有子节点
        for(int i = 0; i < rowCount(index) && (allChecked || allUnchecked); i++) {
            auto child_state = data(this->index(i, 0, index), role).toInt();

            //子节点半选，则直接半选
            switch (child_state) {
            case Qt::PartiallyChecked: allChecked = allUnchecked = false; break;
            case Qt::Unchecked: allChecked = false; break;
            case Qt::Checked: allUnchecked = false; break;
            default: break;
            }
        }

        return setCheckState_(index, allChecked ? Qt::Checked
                                                : allUnchecked ? Qt::Unchecked : Qt::PartiallyChecked);
    }

    default://如果出现此情况就是错了，可以加错误处理
        break;
    }

    return false;
}
